package com.qiudao.commonutil.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Description: 日期时间转换工具类
 * 依赖 joda-time.joda-time
 *      org.apache.commons.lang3
 * @author: gdc
 * @date: 2019/9/1
 * @version 1.0
 */
public class DateTimeUtils {
    public static final String FORMAT_DATE = "yyyy-MM-dd";
    public static final String FORMAT_MONTH = "yyyy-MM";
    public static final String FORMAT_DATETIME = "yyyy-MM-dd HH:mm:ss";
    public static final String FORMAT_FULL_DATETIME = "yyyyMMddHHmmssSSS";
    public static final String FORMAT_FULL_DATE = "yyyyMMdd";
    public static final String FORMAT_PRODUCT_FULL_DATE = "yyyy/MM/dd";
    public static final String FORMAT_FULL_MONTH = "yyyyMM";
    public static final String FORMAT_FULL_HOUR = "H";
    public static final String FORMAT_FULL_MINUTE = "m";
    public static final String FORMAT_FULL_TIME = "yyyyMMddHHmm";
    public static final String FORMAT_FULL_YUE_RI = "M月d日";
    public static final String FORMAT_FULL_DATESEC = "yyyyMMddHHmmss";
    public static final String EXPORT_FORMAT_DATE_IME = "yyyy-MM-dd HH:mm";


    private static final String[] WEEKS = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"};
    private static final String[] NUM_WEEKS = {"一", "二", "三", "四", "五", "六", "日"};

    /**
     * DateFormat枚举
     */
    enum DateFormatKind {
        /**
         * 日期枚举类
         */
        FULL_DF("FULL_DF", FORMAT_FULL_DATETIME),
        FULL_DATE("FULL_DATE", FORMAT_FULL_DATE),
        HOUR("HOUR", FORMAT_FULL_HOUR),
        MINUTE("MINUTE", FORMAT_FULL_MINUTE),
        DATE("DATE", FORMAT_DATE),
        PRUDUCTDATE("PRUDUCTDATE", FORMAT_PRODUCT_FULL_DATE),
        YUE_RI_DATE("YUE_RI_DATE", FORMAT_FULL_YUE_RI),
        FULL_DATE_SEC("FULL_DATESEC", FORMAT_FULL_DATESEC);

        DateFormatKind(String key, String pattern) {
            this.key = key;
            this.pattern = pattern;
        }

        private String key;
        private String pattern;
    }

    /**
     * 用threadLocal维护DateFormat
     */
    private static final ThreadLocal<Map<String, DateFormat>> dfThreadLocal = new ThreadLocal<Map<String, DateFormat>>() {
        @Override
        protected Map<String, DateFormat> initialValue() {
            Map<String, DateFormat> map = new HashMap<String, DateFormat>();
            for (DateFormatKind dateFormatKind : DateFormatKind.values()) {
                map.put(dateFormatKind.key, new SimpleDateFormat(dateFormatKind.pattern));
            }
            return map;
        }
    };

    /**
     * 从threadLocal中取得对应的DateFormat
      */
    private static DateFormat getDateFormat(DateFormatKind dateFormatKind) {
        Map<String, DateFormat> map = dfThreadLocal.get();
        return map.get(dateFormatKind.key);
    }

    /**
     * 将long类型的日期时间转换成yyyyMMddHHmmss格式的数字
     *
     * @param time 日期时间
     * @return 转换之后的数字
     */
    public static long getFormatFullDateSecTime(Long time) {
        if (time == null || time == 0L) {
            return 0;
        }
        return Long.parseLong(getDateFormat(DateFormatKind.FULL_DATE_SEC).format(new Date(time)));
    }

    /**
     * 将long类型的日期时间转换成yyyyMMddHHmmssSSS格式的数字
     *
     * @param time 日期时间
     * @return 转换之后的数字
     */
    public static long getFormatFullDateTime(Long time) {
        if (time == null || time == 0L) {
            return 0;
        }
        return Long.parseLong(getDateFormat(DateFormatKind.FULL_DF).format(new Date(time)));
    }

    /**
     * 将long类型的日期时间转换成yyyyMMdd格式的数字
     *
     * @param time 日期时间
     * @return 转换之后的数字
     */
    public static int getFormatDate(Long time) {
        if (time == null || time == 0L) {
            return 0;
        }
        return Integer.valueOf(getDateFormat(DateFormatKind.FULL_DATE).format(new Date(time)));
    }

    /**
     * 将long类型的日期的时分部分转成分
     *
     * @param time 日期时间
     * @return 转换之后的数字
     */
    public static int getFormatMinute(Long time) {
        if (time == null || time == 0L) {
            return 0;
        }
        return Integer.valueOf(getDateFormat(DateFormatKind.HOUR).format(new Date(time))) * 60 + Integer.valueOf(getDateFormat(DateFormatKind.MINUTE).format(new Date(time)));
    }

    /**
     * 将单据时间转换为表示用的时间（HH:mm）
     *
     * @param time 时间
     * @return HH:mm
     */
    public static String convertToDspTime(Integer time) {
        if (time == null) {
            time = 0;
        }

        int hour = time / 60;
        int mint = time % 60;
        return StringUtils.leftPad(String.valueOf(hour), 2, "0") + ":" + StringUtils.leftPad(String.valueOf(mint), 2, "0");
    }

    /**
     * 将单据日期转换为表示用的日期（yyyy-MM-dd）
     *
     * @param date 单据日期
     * @return yyyy-MM-dd
     */
    public static String convertToDspDate(Integer date) {
        try {
            if (date == null || date == 0) {
                return "";
            }

            String strDate = String.valueOf(date);
            Date tmpDate = getDateFormat(DateFormatKind.FULL_DATE).parse(strDate);
            return getDateFormat(DateFormatKind.DATE).format(tmpDate);
        } catch (ParseException e) {
            return "";
        }
    }

    /**
     * 将单据日期转换为表示用的日期（yyyy/mm/dd）
     *
     * @param date 单据日期
     * @return yyyy/mm/dd
     */
    public static String convertToProductDspDate(Integer date) {
        try {
            if (date == null || date == 0) {
                return "";
            }

            String strDate = String.valueOf(date);
            Date tmpDate = getDateFormat(DateFormatKind.FULL_DATE).parse(strDate);
            return getDateFormat(DateFormatKind.PRUDUCTDATE).format(tmpDate);
        } catch (ParseException e) {
            return "";
        }
    }

    /**
     * 将yyyyMMdd转换为 M月d日
     *
     * @param date yyyyMMdd
     * @return MM月dd日
     */
    public static String convertToYueRiDate(Integer date) {
        try {
            if (date == null || date == 0) {
                return "";
            }

            String strDate = String.valueOf(date);
            Date tmpDate = getDateFormat(DateFormatKind.FULL_DATE).parse(strDate);
            return getDateFormat(DateFormatKind.YUE_RI_DATE).format(tmpDate);
        } catch (ParseException e) {
            return "";
        }
    }


    /**
     * 将格式为yyyyMMddHHmmssSSS 格式转化 yyyy-MM-dd HH:mm
     *
     * @param time
     * @return
     */
    public static String getTimeStr(Long time) {
        if (time == null) {
            return "0";
        }
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_FULL_DATETIME).parseDateTime(time.toString());
        return dateTime.toString(EXPORT_FORMAT_DATE_IME);
    }

    /**
     * 时间戳 格式转化 yyyy-MM-dd HH:mm
     *
     * @param time
     * @return
     */
    public static String convertToTime(Long time) {
        if (time == null) {
            return "0";
        }
        DateTime dateTime = new DateTime(time);
        return dateTime.toString(EXPORT_FORMAT_DATE_IME);
    }

    /**
     * 时间戳 格式转化 yyyy-MM-dd HH:mm:ss
     *
     * @param time
     * @return
     */
    public static String convertToTimeSS(Long time) {
        if (time == null) {
            return "0";
        }
        DateTime dateTime = new DateTime(time);
        return dateTime.toString(FORMAT_DATETIME);
    }

    /**
     * 时间戳 格式转化 yyyy-MM-dd HH:mm
     *
     * @param time
     * @return
     */
    public static String convertToDate(Long time) {
        if (time == null) {
            return "0";
        }
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_FULL_DATETIME).parseDateTime(time.toString());
        return dateTime.toString(FORMAT_DATE);
    }

    /**
     * 将格式为yyyyMMddHHmmssSSS 格式转化 yyyyMMddHHmm
     *
     * @param time
     * @return
     */
    public static String getTimeStrS(Long time) {
        if (time == null) {
            return "0";
        }
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_FULL_DATETIME).parseDateTime(time.toString());
        return dateTime.toString(FORMAT_FULL_TIME);
    }

    /**
     * 将Integer的yyyyMMdd转为long的yyyyMMddHHmmssSSS(添加00_00_00_000)
     *
     * @param startDate
     * @return
     */
    public static Long fullDateIntegerToLong(Integer startDate) {
        DateTime dateTimeStartDate = DateTimeFormat.forPattern(FORMAT_FULL_DATE).parseDateTime(startDate.toString());
        return Long.parseLong(dateTimeStartDate.toString(FORMAT_FULL_DATETIME));
    }

    /**
     * 将long的yyyyMMddHHmmssSSS转化为Integer的yyyyMMdd
     *
     * @param time
     * @return
     */
    public static Integer longToFullDateInteger(Long time) {
        if (time == null) {
            return 0;
        }
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_FULL_DATETIME).parseDateTime(time.toString());
        return Integer.parseInt(dateTime.toString(FORMAT_FULL_DATE));
    }

    /**
     * 返回前后包含的时间区间，返回的时间格式为(Long型数据)： yyyyMMddHHmmssSSS
     *
     * @param dateMode
     * @return
     */
    public static DataPair getDatePair(DateModeEnum dateMode) {
        Date today = DateUtil.trunc(new Date());
        Long startDate = null;
        Long endDate = null;

        if (DateModeEnum.YESTERDAY.equals(dateMode)) {
            Date yesterday = DateUtil.addDays(today, -1);
            startDate = DateTimeUtils.getFormatFullDateTime(yesterday.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(DateUtil.getEndDate(yesterday).getTime());
        } else if (DateModeEnum.TODAY.equals(dateMode)) {
            startDate = DateTimeUtils.getFormatFullDateTime(today.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(DateUtil.getEndDate(today).getTime());
        } else if (DateModeEnum.THIS_WEEK.equals(dateMode)) {
            int diff = DateUtil.getDayOfWeek(today);
            // 为周日
            if (1 == diff) {
                diff = 8;
            }
            Date firstOfWeek = DateUtil.addDays(today, 0 - (diff - 2));
            startDate = DateTimeUtils.getFormatFullDateTime(firstOfWeek.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(DateUtil.getEndDate(today).getTime());
        } else if (DateModeEnum.THIS_MONTH.equals(dateMode)) {
            Date firstOfMonth = DateUtil.getFirstDayOfMonth(today);
            startDate = DateTimeUtils.getFormatFullDateTime(firstOfMonth.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(DateUtil.getEndDate(today).getTime());
        } else if (DateModeEnum.PREV_MONTH.equals(dateMode)) {
            Date firstOfLastMonth = DateUtil.getFirstDayOfMonth(DateUtil.addMonths(today, -1));
            Date endOfLastMonth = DateUtil.addDays(DateUtil.addMonths(firstOfLastMonth, 1), -1);
            startDate = DateTimeUtils.getFormatFullDateTime(firstOfLastMonth.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(DateUtil.getEndDate(endOfLastMonth).getTime());
        }

        DataPair pair = new DataPair(startDate, endDate);
        return pair;
    }

    /**
     * 返回时间区间，适用 startTime <= dateTime < endTime 场景，返回的时间格式为(Long型数据)： yyyyMMddHHmmssSSS
     *
     * @param dateMode
     * @return
     */
    public static DataPair getDatePair2(DateModeEnum dateMode) {
        Date today = DateUtil.trunc(new Date());
        Long startDate = null;
        Long endDate = null;

        if (DateModeEnum.YESTERDAY.equals(dateMode)) {
            Date yesterday = DateUtil.addDays(today, -1);
            startDate = DateTimeUtils.getFormatFullDateTime(yesterday.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(today.getTime());
        } else if (DateModeEnum.TODAY.equals(dateMode)) {
            Date nextDay = DateUtil.addDays(today, 1);
            startDate = DateTimeUtils.getFormatFullDateTime(today.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(nextDay.getTime());
        } else if (DateModeEnum.THIS_WEEK.equals(dateMode)) {
            int diff = DateUtil.getDayOfWeek(today);
            // 为周日
            if (1 == diff) {
                diff = 8;
            }
            Date nextDay = DateUtil.addDays(today, 1);
            Date firstOfWeek = DateUtil.addDays(today, 0 - (diff - 2));
            startDate = DateTimeUtils.getFormatFullDateTime(firstOfWeek.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(nextDay.getTime());
        } else if (DateModeEnum.THIS_MONTH.equals(dateMode)) {
            Date firstOfMonth = DateUtil.getFirstDayOfMonth(today);
            Date nextDay = DateUtil.addDays(today, 1);
            startDate = DateTimeUtils.getFormatFullDateTime(firstOfMonth.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(nextDay.getTime());
        } else if (DateModeEnum.PREV_MONTH.equals(dateMode)) {
            Date firstOfLastMonth = DateUtil.getFirstDayOfMonth(DateUtil.addMonths(today, -1));
            Date endOfLastMonth = DateUtil.addMonths(firstOfLastMonth, 1);
            startDate = DateTimeUtils.getFormatFullDateTime(firstOfLastMonth.getTime());
            endDate = DateTimeUtils.getFormatFullDateTime(endOfLastMonth.getTime());
        }

        DataPair pair = new DataPair(startDate, endDate);
        return pair;
    }

    /**
     * 返回日期区间，适用 startDate <= date < endDate 场景，返回的时间格式为(Long型数据)： yyyyMMdd
     *
     * @param dateMode
     * @return
     */
    public static DataPair getDatePair3(DateModeEnum dateMode) {
        Date today = DateUtil.trunc(new Date());
        Integer startDate = null;
        Integer endDate = null;

        if (DateModeEnum.YESTERDAY.equals(dateMode)) {
            Date yesterday = DateUtil.addDays(today, -1);
            startDate = DateTimeUtils.getFormatDate(yesterday.getTime());
            endDate = DateTimeUtils.getFormatDate(today.getTime());
        } else if (DateModeEnum.TODAY.equals(dateMode)) {
            Date nextDay = DateUtil.addDays(today, 1);
            startDate = DateTimeUtils.getFormatDate(today.getTime());
            endDate = DateTimeUtils.getFormatDate(nextDay.getTime());
        } else if (DateModeEnum.THIS_WEEK.equals(dateMode)) {
            int diff = DateUtil.getDayOfWeek(today);
            // 为周日
            if (1 == diff) {
                diff = 8;
            }
            Date nextDay = DateUtil.addDays(today, 1);
            Date firstOfWeek = DateUtil.addDays(today, 0 - (diff - 2));
            startDate = DateTimeUtils.getFormatDate(firstOfWeek.getTime());
            endDate = DateTimeUtils.getFormatDate(nextDay.getTime());
        } else if (DateModeEnum.THIS_MONTH.equals(dateMode)) {
            Date firstOfMonth = DateUtil.getFirstDayOfMonth(today);
            Date nextDay = DateUtil.addDays(today, 1);
            startDate = DateTimeUtils.getFormatDate(firstOfMonth.getTime());
            endDate = DateTimeUtils.getFormatDate(nextDay.getTime());
        } else if (DateModeEnum.PREV_MONTH.equals(dateMode)) {
            Date firstOfLastMonth = DateUtil.getFirstDayOfMonth(DateUtil.addMonths(today, -1));
            Date endOfLastMonth = DateUtil.addMonths(firstOfLastMonth, 1);
            startDate = DateTimeUtils.getFormatDate(firstOfLastMonth.getTime());
            endDate = DateTimeUtils.getFormatDate(endOfLastMonth.getTime());
        }

        DataPair pair = new DataPair(new Long(startDate), new Long(endDate));
        return pair;
    }

    /**
     * 将日期和时间转化为yyyyMMddHHmmssSSS
     *
     * @param date yyyyMMdd
     * @param time 当前时间为今天第几分 如6：30则为390
     * @return
     */
    public static Long getDateTimeByDateAndTime(Integer date, Integer time) {
        String dateTime = String.valueOf(date);
        if (null == time) {
            time = 0;
        }
        int hour = time / 60;
        int mint = time % 60;
        // 组成yyyyMMddHHmmssSSS
        dateTime = dateTime + StringUtils.leftPad(String.valueOf(hour), 2, "0") + StringUtils.leftPad(String.valueOf(mint), 2, "0") + "00000";

        return Long.valueOf(dateTime);
    }

    /**
     * 获取当前所在的分钟数
     *
     * @param sysTime
     * @return
     */
    public static int getDayMinutes(Long sysTime) {
        if (sysTime == 0) {
            return 0;
        }

        DateTime dateTime = new DateTime(sysTime);
        int minutes = dateTime.getHourOfDay() * 60 + dateTime.getMinuteOfHour();
        return minutes;
    }

    /**
     * 将格式为yyyyMMddHHmmssSSS 格式转化 yyyy-MM-dd HH:mm:ss
     *
     * @param time
     * @return
     */
    public static String getDateTimeStr(Long time) {
        if (null == time) {
            return "0";
        }
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_FULL_DATETIME).parseDateTime(time.toString());
        return dateTime.toString(FORMAT_DATETIME);
    }

    /**
     * 将格式为yyyyMMddHHmmss 格式转化 yyyy-MM-dd HH:mm:ss
     *
     * @param time
     * @return
     */
    public static String getDateTimeStrBySec(Long time) {
        if (null == time) {
            return "0";
        }
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_FULL_DATESEC).parseDateTime(time.toString());
        return dateTime.toString(FORMAT_DATETIME);
    }

    /**
     * 将格式为yyyyMMddHHmmss 格式转化 yyyyMMddHHmmssSSS
     *
     * @param time
     * @return
     */
    public static Long getFullDateBySec(Long time) {
        if (null == time) {
            return 0L;
        }
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_FULL_DATESEC).parseDateTime(time.toString());
        return Long.valueOf(dateTime.toString(FORMAT_FULL_DATETIME));
    }

    /**
     * 将格式为yyyy-MM-dd 格式转化 yyyyMMdd
     *
     * @param date
     * @return
     */
    public static Integer convertToDate(String date) {
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_DATE).parseDateTime(date);
        return Integer.parseInt(dateTime.toString(FORMAT_FULL_DATE));
    }

    /**
     * 将格式为yyyy-MM格式转化 yyyyMM
     *
     * @param date
     * @return
     */
    public static Integer convertToMonth(String date) {
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_MONTH).parseDateTime(date);
        return Integer.parseInt(dateTime.toString(FORMAT_FULL_MONTH));
    }

    /**
     * 根据格式为yyyy-MM-dd 日期，获取是周几
     *
     * @param date
     * @return
     */
    public static String getDayOfWeek(String date) {
        if (StringUtils.isBlank(date)) {
            return null;
        }
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_DATE).parseDateTime(date);
        int dayOfWeek = dateTime.getDayOfWeek();
        return NUM_WEEKS[dayOfWeek - 1];
    }

    /**
     * 根据格式为yyyyMMdd 日期，获取是周几
     *
     * @param date
     * @return
     */
    public static String getDayOfWeekFormatFullDate(String date) {
        if (StringUtils.isBlank(date)) {
            return null;
        }
        DateTime dateTime = DateTimeFormat.forPattern(FORMAT_FULL_DATE).parseDateTime(date);
        int dayOfWeek = dateTime.getDayOfWeek();
        return NUM_WEEKS[dayOfWeek - 1];
    }

    /**
     * 将供应链时间格式转换为时间戳
     *
     * @param time
     * @return
     */
    public static long convertScmTime2UnixTime(Long time) {
        if (time == null || time == 0L) {
            return 0L;
        }
        try {
            Date date = getDateFormat(DateFormatKind.FULL_DF).parse(String.valueOf(time));
            return date.getTime();
        } catch (ParseException e) {
            return 0L;
        }
    }

    public static void main(String[] args) {
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair(DateModeEnum.YESTERDAY)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair(DateModeEnum.TODAY)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair(DateModeEnum.THIS_WEEK)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair(DateModeEnum.THIS_MONTH)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair(DateModeEnum.PREV_MONTH)));
        // //
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair2(DateModeEnum.YESTERDAY)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair2(DateModeEnum.TODAY)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair2(DateModeEnum.THIS_WEEK)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair2(DateModeEnum.THIS_MONTH)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair2(DateModeEnum.PREV_MONTH)));
        //
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair3(DateModeEnum.YESTERDAY)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair3(DateModeEnum.TODAY)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair3(DateModeEnum.THIS_WEEK)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair3(DateModeEnum.THIS_MONTH)));
        System.out.println(ToStringBuilder.reflectionToString(DateTimeUtils.getDatePair3(DateModeEnum.PREV_MONTH)));
    }

}

